/*
测试环境：
    CPU:General Purpose Processor 2.5GHz
    RAM: 2Gi
    ROM: 40GiB
    OS:ubuntu-20.04 server 64bit （2核|2G)

测试三要素： 测试环境、测试方法、测试结果
测试工具的编写：
    1、可以控制写线程数量
    2、可以控制写日志的总数量
    3、分别对同步日志器和异步日志器进行各自的性能测试
        需要测试单写日志线程的性能
        需要多写日志线程的性能
    实现：封装一个接口， 传入日志器名称， 线程数量， 日志数量， 单条日志大小
    在接口内， 创建指定的线程， 各自负责一部分日志的输出，
    在输出之前计时开始， 在输出完毕之后计时结束， 所耗时间 = 结束时间 - 起始时间
    每秒输出量 = 日志数量 / 总耗时
    每秒输出大小 = 日志数量 * 单条日志大小 / 总耗时
注意： 一部日志输出这里， 我们启动非安全模式， 纯内存吸入（不去考虑实际落地的时间）
*/

#include "../logs/mylog.h"

void bench(const std::string& name, size_t thr_count, size_t msg_count, size_t msg_len)
{
    /*
        1、获取一个日志器
        2、组织指定长度的日志消息
        3、创建指定数量的线程
        4、线程函数内部开始计时
        5、开始循环写日志
        6、线程函数内部结束计时
        7、计算总耗时
        8、进行输出打印    
    */

    mian_yang::Logger::ptr logger = mian_yang::getlogger(name);
    if (logger == nullptr)
    {
        return;
    }

    std::cout << "测试日志: " << msg_count << " 条, 总大小" << msg_count * msg_len / 1024 << "KB" << std::endl;

    //组织消息
    std::string msg(msg_len - 1, 'A');  /*少一个字节是为了给末尾添加换行符*/

    //创建线程
    std::vector<std::thread> threads;   /*管理线程*/
    std::vector<double> cost_arry(thr_count);
    size_t msg_per_thr = msg_count / thr_count;   /*总日志数量 / 总线程数量就是每个线程要输出的日志数量*/
    for (int i = 0; i < thr_count; i++)
    {
        threads.emplace_back([&, i]()
        {
            auto start = std::chrono::high_resolution_clock::now();  
            
            //开始循环写日志
            for (int j = 0; j < msg_per_thr; j++)
            {
                logger->fatal("%s", msg.c_str());
            }
            //6.线程函数内部结束计时
            auto end = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double> cost = end - start; 
            cost_arry[i] = cost.count();    /*将所经历的秒数直接赋值进数组， 便于线程完毕之后进行耗时统计*/
            std::cout << "线程：" << i << ":" << "\t输出日志数量:" << msg_per_thr << ", 耗时:" << cost.count() << std::endl;
        });   /*构造并插入*/
    }

    for (int i = 0; i < thr_count; i++)
    {
        threads[i].join();    /*关闭线程*/
    }

    //计算总耗时， 在多个线程中， 每个线程都会耗费时间， 但是线程时并发处理的， 因此好事最高的那个就是总时间
    double max_cost = cost_arry[0];
    for (int i = 0; i < thr_count; i++) max_cost = max_cost < cost_arry[i] ? cost_arry[i] : max_cost;
    size_t msg_per_sec = msg_count / max_cost;
    size_t size_per_sec = msg_count * msg_len / (max_cost * 1024);
    
    //进行输出打印
    std::cout << "每秒输出日志数量: " << msg_per_sec << "条\n";
    std::cout << "每秒输出日志大小: " << size_per_sec << "KB\n";
    

}

void sync_bench()
{
    /*创建一个工厂， 这个工厂是全局工厂。 */                                                /*利用*全局工厂初始化工厂*/
    std::unique_ptr<mian_yang::LoggerBuilder> Lgbder(new mian_yang::GlobalLoggerBuilder()); /*不允许抽象类型创建对象， 那么可以使用抽象指针。*/

    /*全局工厂各项属性进行初始化*/
    Lgbder->buildLoggerName("sync_logger");
    Lgbder->buildLoggerLevel(mian_yang::LogLevel::value::DEBUG);
    Lgbder->buildFormatter("%m%n");
    // Lgbder->buildEnableUnSageAsync(); /*开启非安全模式，为了将实际落地时间排除在外*/
    Lgbder->buildLoggerType(mian_yang::LoggerType::LOGGER_SYNC);
    Lgbder->buildSink<mian_yang::FileSink>("./logfile/test.log/file.log");
    Lgbder->buildSink<mian_yang::RollSink>("./logfile/test.log/roll-", 1024 * 1024);
    Lgbder->build();
    bench("sync_logger", 1, 1000000, 100);
    // bench("sync_logger", 3, 1000000, 100);            
                                                      /*
                                                        100万条， 多线程比单线程慢， 是因为单线程不涉及所冲突。
                                                        而多线程需要加锁， 写日志是一个串行的过程。所以
                                                        多线程并不能减少IO的效率， 反而增加了加锁产生的时间消耗
                                                      */
}    /*
        异步情况下， 考察的是cpu和内存的性能。同步受限于硬盘的性能。 同步下的单线程与多线程的区别， 异步下的多线程与单线程的区别。
        cpu和内存的延展性更高。 所以异步提升更加明显。
     */
void async_bench()
{

}


int main()
{
    sync_bench();
    return 0;
}
